#include "Parser.h"

Parser::Parser(string dir) {
	this->docFile = new ArchivoDocumentos("Docs.bin");
	this->docFile->setHeader(dir);
	this->pathRaiz = dir;
	this->cantFiles = 0;
	this->parseFiles(dir);
}

void Parser::parseFiles(string dir) {

	DIR *dp = opendir(dir.c_str());
	struct dirent *dirp;
	ArchivoAuxiliar *archivo = NULL;

	while ((dirp = readdir(dp)) != NULL) {
		string path = string(dir);
		path.append("/");
		path.append(string(dirp->d_name));
		if (dirp->d_type == DT_DIR) {
			string directorioActual = string(dirp->d_name);
			if (directorioActual != "." && directorioActual != "..") {
				parseFiles(path);
			}
		} else {
			this->cantFiles += 1;
			parseFile(path);
			archivo = FileHandler::getInstance()->merge(archivo, &buffer);
			emptyBuffer();
		}
	}
	unsigned int nTerminos=FileHandler::getInstance()->getNTerminos();
	unsigned int nDocs=FileHandler::getInstance()->getNDocs();
	//cout<<"nDocs:"<< nDocs<<endl;
	//cout<<"nTerminos:"<< nTerminos<<endl;
	if(nDocs>SVD::dimension && nTerminos>SVD::dimension){
		SVD::getInstance()->calculate(archivo,nDocs,nTerminos);
	}else{
		cout <<"No se peude reducir la matriz a estas dimensiones"<<endl;
	}

	delete (archivo);
	closedir(dp);
}

void Parser::parseFile(string path) {
	cout << "Parsing File: " << path << endl;
	ifstream file(path.c_str());
	string line;

	if (file.is_open()) {
		while (file.good()) {
			size_t found = path.find_first_not_of(this->pathRaiz);
			string filePath = path.substr(found, this->pathRaiz.size());
			this->docFile->add(this->cantFiles, filePath);
			getline(file, line);
			parseLine(line);
		}
		file.close();
	}
}

void Parser::emptyBuffer() {
	for (unsigned int i = 0; i < buffer.size(); i++) {
		RegistroAuxiliar* reg = buffer.at(i);
		if (reg != NULL)
			delete reg;
	}

	buffer.clear();
}

void Parser::parseLine(string line) {
	char* token = strtok((char*) line.c_str(), " ,.-");
	if (token != NULL) {
		stemToken(string(token));
		while (token != NULL) {
			token = strtok(NULL, " ,.-");
			if (token != NULL && strlen(token) > 1)
				stemToken(string(token));
		}
	}
}

void Parser::stemToken(string token) {

	std::wstring word;
	stemming::english_stem<> StemEnglish;
	wchar_t* UnicodeTextBuffer = new wchar_t[token.length() + 1];
	std::wmemset(UnicodeTextBuffer, 0, token.length() + 1);
	std::mbstowcs(UnicodeTextBuffer, token.c_str(), token.length());
	word = UnicodeTextBuffer;
	StemEnglish(word);
	//std::wcout << L"(English) Original text:\t" << token.c_str() << std::endl;
	//std::wcout << L"(English) Stemmed text:\t" << word.c_str() << std::endl;
	addToken(string(word.begin(), word.end()));
}

void Parser::addToken(string token) {

	vector<RegistroAuxiliar*>::iterator low;
	RegistroAuxiliar* newReg = new RegistroAuxiliar();
	vector<uint16_t> frecuencias;
	vector<uint32_t> documentos;
	newReg->setTermino(token);
	documentos.push_back(this->cantFiles);
	newReg->setNroDocs(documentos);
	frecuencias.push_back(1);
	newReg->setFrecuencias(frecuencias);
	sort(buffer.begin(), buffer.end(), RegistroAuxiliar::comparator);
	low = lower_bound(buffer.begin(), buffer.end(), newReg,
			RegistroAuxiliar::comparator);
	int position = int(low - buffer.begin());
	if (low != buffer.end()
			&& (buffer.at(position)->getTermino()).compare(token) == 0) {
		buffer.at(position)->getFrecuencias()->at(0) += 1;
	} else {
		buffer.push_back(newReg);
	}
}

Parser::~Parser() {
	emptyBuffer();
	delete (docFile);
}

